from math import sqrt
from element_tree import *
import random
from random import random as rand
from math import sin, cos, sqrt ,pi, floor
import pygame
import pickle

randint = lambda N: random.randint(0, N-1)

class ELEMENT_TYPE:
    MOVO = 0
    CELI = 1
    LATA = 2
    NINI = 3
    SADA = 4
    LATA_MOVO = 5
    GUSHA = 6
    MOVO_ZIDA = 7
    CELI_ZIDA = 8
    LATA_ZIDA = 9
    NINI_ZIDA = 10
    SADA_ZIDA = 11
    LATA_MOVO_ZIDA = 12
    GUSHA_ZIDA = 13
    TIME = 14
    MAX_ID = 14

    def type_name(type):
        if(type == ELEMENT_TYPE.MOVO):
            return 'movo'
        elif(type == ELEMENT_TYPE.CELI):
            return 'celi'
        elif(type == ELEMENT_TYPE.LATA):
            return 'lata'
        elif(type == ELEMENT_TYPE.NINI):
            return 'nini'
        elif(type == ELEMENT_TYPE.SADA):
            return 'sada'
        elif(type == ELEMENT_TYPE.LATA_MOVO):
            return 'lata_movo'
        elif(type == ELEMENT_TYPE.GUSHA):
            return 'gusha'
        elif(type == ELEMENT_TYPE.MOVO_ZIDA):
            return 'movo_zida'
        elif(type == ELEMENT_TYPE.CELI_ZIDA):
            return 'celi_zida'
        elif(type == ELEMENT_TYPE.LATA_ZIDA):
            return 'lata_zida'
        elif(type == ELEMENT_TYPE.NINI_ZIDA):
            return 'nini_zida'
        elif(type == ELEMENT_TYPE.SADA_ZIDA):
            return 'sada_zida'
        elif(type == ELEMENT_TYPE.LATA_MOVO_ZIDA):
            return 'lata_movo_zida'
        elif(type == ELEMENT_TYPE.GUSHA_ZIDA):
            return 'gusha_zida'
        elif(type == ELEMENT_TYPE.TIME):
            return 'time'

class GAMEPHASE:
    BEGIN = 0
    MAIN = 1
    WIN = 2
    LOSE = 3
    CREATING = 4

with open('./resources/settings.pkl', 'rb') as fp:
    custum_settings = pickle.load(fp)

# load resources
img_top = [pygame.image.load('./resources/pictures/%s.png'%(ELEMENT_TYPE.type_name(elem))) 
            for elem in range(ELEMENT_TYPE.MAX_ID)]
img_hidden = [pygame.image.load('./resources/pictures/%s_hidden.png'%(ELEMENT_TYPE.type_name(elem))) 
            for elem in range(ELEMENT_TYPE.MAX_ID)]



class GenshinElemNode(ElemNode):
    elem_type: ELEMENT_TYPE
    pos: tuple
    radius: float
    
    def __init__(self,elem_type, pos, radius) -> None:
        super().__init__()
        self.elem_type = elem_type
        self.pos = pos
        self.radius = radius

    

def overlap_cmp_fun(top_node: GenshinElemNode, bottom_node: GenshinElemNode):
    distance = sqrt((top_node.pos[0] - bottom_node.pos[0]) ** 2 + (top_node.pos[1] - bottom_node.pos[1]) ** 2 )
    return distance < (top_node.radius + bottom_node.radius)

def pos_on_elem(pos:tuple, node:GenshinElemNode):
    distance = sqrt((node.pos[0] - pos[0])**2 + (node.pos[1] - pos[1])**2)
    return distance < node.radius

class ElemStack:
    capacity: int
    elem_list: list
    elem_count: list
    def __init__(self, capacity=7) -> None:
        self.capacity = capacity
        self.elem_list = []
        self.elem_count = [0] * ELEMENT_TYPE.MAX_ID
    
    def append(self, elem_type: ELEMENT_TYPE):
        if(self.elem_count[elem_type] == 0):
            self.elem_list.append(elem_type)
        self.elem_count[elem_type] += 1

        if(self.elem_count[elem_type] == 3):
            self.elem_count[elem_type] = 0
            self.elem_list.remove(elem_type)
            get_elem = True
        else:
            get_elem = False
            

        if get_elem:
            return elem_type
        else:
            return -1

    def is_full(self):
        if(sum(self.elem_count) >= self.capacity):
            return True
        else:
            return False

    def create_pile(self):
        pass

    def render(self, window: pygame.Surface, x_start, x_step, y):
        curr_x = x_start
        for elem_type in self.elem_list:
            for j in range(self.elem_count[elem_type]):
                rect = img_top[elem_type].get_rect(center=(curr_x, y))
                window.blit(img_top[elem_type], rect)
                curr_x += x_step

class ElemGenerator:
    N_triplets: int
    N_remaining: int 
    capacity: int
    num_triplets: int
    stack: list
    triplet_stack:list
    def __init__(self, N_triplets, capacity = 7, num_triplets = 3) -> None:
        self.N_triplets = N_triplets
        self.capacity = capacity
        self.num_triplets = num_triplets
        self.stack = []
        self.triplet_stack = []
        self.N_remaining = N_triplets

    def generate(self):
        result = []
        
        n0 = floor(self.capacity/self.num_triplets)
        for j in range(n0):
            new_elem = randint(ELEMENT_TYPE.MAX_ID)
            self.stack += [new_elem] * self.num_triplets 
        
        self.N_remaining -= n0

        while(self.N_remaining > 0 or len(self.triplet_stack)>0):
            if(len(self.triplet_stack) == 0):
                new_elem = randint(ELEMENT_TYPE.MAX_ID)
                self.triplet_stack = [new_elem] * self.num_triplets
                self.N_remaining -= 1
            
            while(len(self.stack) < self.capacity):
                self.stack.append(self.triplet_stack.pop())
            id = randint(len(self.stack))
            result.append(self.stack.pop(id))

        while(self.stack):
            id = randint(len(self.stack))
            result.append(self.stack.pop(id))
        return result